﻿using System;
using System.Collections.Generic;
using System.Linq;
using Game1942.Library.Background;
using Game1942.Library.Controller;
using Game1942.Library.Planes;
using Game1942.Library.View;
using Game1942.Library.Weapons;
using Game1942.Library.Provider;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace Game1942.Library
{

    public sealed class Driver     //Driver is a Singleton
    {
        private static Driver instance;
        public List<Aircraft> enemyList;
        public List<ComputerElement> computerList;

        public List<Provider<ComputerElement>> providerList;
        public List<IView> viewList;

        private Algo42 player = new Algo42();
        private Background.Background map;
        public int Score { get; set; }

        private ContentManager contentManager;

        private AircraftFactory factory;
        private int level = 1;

        private Driver()
        {
            
        }

        public static Driver Instance
        {
            get { return instance ?? (instance = new Driver()); }
        }

        public static void Clear()
        {
            instance = null;
        }

        public void SetContentManager(ContentManager contentManagerValue)
        {
            this.contentManager = contentManagerValue;
        }

        public void EscapeMode()
        {
            foreach (var aircraft in enemyList)
            {
                if ((aircraft.Located))
                {
                    aircraft.Escape();
                }
                
            }
        }

        public Algo42 Player
        {
            get { return player; }
            set { player = value; }
        }

        public void AddLiveUnit(ComputerElement computerItem,int width,int height, String viewName)
        {
            //Creo la vista y el proveedor
            var computerElementView = new ComputerElementView(computerItem.ActualPosition,width,height);
            var computerElementProvider = new Provider<ComputerElement>();

            //Cargo la textura
            computerElementView.LoadContent(contentManager.Load<Texture2D>(viewName));

            //Suscribo la vista al proveedor
            computerElementView.Subscribe(computerElementProvider);

            //Llego la hora de enlistar todas las cosas
            computerList.Add(computerItem);//Enlisto el objeto
            viewList.Add(computerElementView);//Enlisto la vista
            providerList.Add(computerElementProvider);//Enlisto el proveedor

        }

        public void AddEnemy(Aircraft enemy)
        {
            enemyList.Add(enemy);
        }

        //Remove the computer elements are deads
        public void RemoveDeadUnits()
        {
           
            /************************Esto es realmente asqueroso***********************/
            foreach (var element in enemyList)
            {
                if (!element.Alive)
                {
                    Score += element.Score;

                    var newExplosion = new ExplosionView(element.ActualPosition, 50, 50);
                    newExplosion.LoadContent(contentManager.Load<Texture2D>("Explosions/explosionPic"), 
                        contentManager.Load<SoundEffect>("Explosions/explosionSound"));
                    viewList.Add(newExplosion);
                }
            }
            var newList = computerList.Where(computerElement => computerElement.Alive).ToList();
            computerList = newList;
            enemyList = enemyList.Where(enemy => enemy.Alive).ToList();
            /*************************************************************************/
        }

        public void RemoveEmptyProviders()
        {
            //filtra los proveedores que no tienen observers
            providerList = providerList.Where(provider => provider.GetAmountOfObservers() != 0).ToList();
        }

        public void RemoveNotVisibleViews()
        {
            var auxList = new List<IView>();
            foreach (IView view in viewList)
            {
                if (view.Visible())
                {
                    auxList.Add(view);
                }
                else
                {    //Desinscribo del proveedor a la que esta muerta
                    try
                    {
                        ((IObserver<ComputerElement>)view).OnCompleted();
                    }
                    catch (Exception){}
                    
                }
            }
            viewList = auxList;
        }

        public void Play()
        {
            factory.RequestInsertEnemies();
            try
            {
                var auxList = new List<ComputerElement>(computerList);
                foreach (var computerElement in auxList)
                {
                    computerElement.Live();
                }
            }
            catch (Exception){}
        }

        public void StartLevel(int leVel)
        {
            Background.Background.Clear();
            map = Background.Background.Instance;
            /*if (!player.InitializeLocation(new Point(340, 500)))
            {
                throw new ApplicationException("The Player could not be located.");
            }*/
            enemyList = new List<Aircraft>();
            computerList = new List<ComputerElement>();
            providerList = new List<Provider<ComputerElement>>();
            viewList = new List<IView>();
            //Background.Background.Clear();
            //map = Background.Background.Instance;
            Score = 0;
            level = leVel;
            var lifes = player.Lifes;
            player = new Algo42 {Lifes = lifes};
            //player.SetPosition(new Point(340,500));
            if (!player.InitializeLocation(new Point((Constants.Screen.Width - Constants.Algo42.Width) / 2, (Constants.Screen.Height - Constants.Algo42.Height))))
            {
                throw new ApplicationException("The Player could not be located.");
            }
            factory = new AircraftFactory();
            factory.InitializeAtLevel(leVel);
        }

        public void StartGame()
        {
            StartLevel(1);
        }

        public bool EndGame()
        {
            var noLifesRemaining = (player.Lifes == 0);
            return noLifesRemaining;
        }

        public bool IsLevelFinished()
        {
            var scoreReached = Score > Constants.WinScore;
            var noEnemiesLeft = ((enemyList.Count == 0) && factory.IsEmpty());
            if (!player.Alive)
            {
                StartLevel(level);
            }
            else if (scoreReached || noEnemiesLeft)
            {
                StartLevel(level++);
            }
            else return false;
            return true;
        }
    }
}
        